<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue MVVM模式的简单实现_原始版</title>
</head>
<body>
<h3>Vue mvvm simple model</h3>
<div id="app">
  <h2 v-text="title"></h2>
  <p v-text="name"></p>
  <input v-model="name">
</div>

<script>
function Vue(opt) {
  this.data = opt.data || {};
  this.$el = document.querySelector(opt.el) || document.body;
  var textDom = this.$el.querySelectorAll('[v-text]');
  var modelDom = this.$el.querySelectorAll('[v-model]');

  var self = this;

  function observe(data) {
    // 设置开始和递归终止条件
    if (!data || typeof data !== 'object') {
      return;
    }
    // 不能直接使用for循环，避开闭包陷阱
    Object.keys(data).forEach(function (key) {
      defineReactive(data, key, data[key]);
    })
  }

  function defineReactive(data, key, val) {
    observe(val);   // 递归对象属性到基本类型为止
    Object.defineProperty(data, key, {
      enumerable  : true,    // 枚举
      configurable: false, // 不可再配置
      get         : function () {
        console.log('getter');
        return val;
      },
      set         : function (newVal) {
        if (val === newVal) {
          return;
        }
        console.log('setter');
        val = newVal;  // setter本身已经做了赋值，val作为一个闭包变量，保存最新值
        model2View();
      },
    })
  }

  function model2View() {
    textDom.forEach(function (node) {
      node.innerText = self.data[node.getAttribute('v-text')];
    });
  }

  function watch() {
    modelDom.forEach(function (node) {
      node.addEventListener('keyup', function () {
        self.data[node.getAttribute('v-model')] = node.value;
      });
    });
  }

  observe(this.data);
  model2View();
  watch();
}

var vm = new Vue({
  el  : '#app',
  data: {
    name : 'Vue',
    title: 'Hello Vue!',
  },
});
</script>
</body>
</html>